const fs = require("fs");
const Store = require("electron-store");
const store = new Store();
const path = require("path");
const { dialog } = require("electron");
const cmd = require("node-cmd");
import { shell } from "electron";
const sizeOf = require("image-size");
import { cleanCssLinks, cssRelink } from "./html/cssAnalyser";
import {
  addMusicToIndex,
  changeTitle,
  cleanHtmlLinks,
  htmlIntegration,
  htmlReLink,
  unlinkImg,
} from "./html/htmlAnalyser";
import {
  runServer,
  closeServer,
  fileStructureInterface,
  removeIdFromFile,
  folderTreeType,
} from "./server";
import {
  appendToBody,
  copyDir,
  copyIfNotExist,
  delDir,
  quoteCss,
  updateStructure,
} from "./html/util";

const paths = {
  project: path.resolve(__dirname, ".pro"),
  res: path.resolve(__dirname, ".pro/res"),
  js: path.resolve(__dirname, ".pro/res/js"),
  img: path.resolve(__dirname, ".pro/res/img"),
  css: path.resolve(__dirname, ".pro/res/css"),
  tmp: path.resolve(__dirname, ".pro/tmp"),
  equip: path.resolve(__dirname, ".pro/res/img/tmp"),
  icon: path.resolve(__dirname, ".pro/res/img/tmp/icon"),
};
export const getProjectPath = () => paths.project; // __dirname + "\\.pro";
export const getProjectResPath = () => paths.res;
export const getProjectJsPath = () => paths.js;
export const getProjectImgPath = () => paths.img;
export const getProjectCssPath = () => paths.css;
export const getProjectTmpPath = () => paths.tmp;
export const getProjectEquipPath = () => paths.equip;
export const getProjectIconPath = () => paths.icon;
export const getTemplatesPath = () => "D:/Desktop/test/html/templates/";

let initServer = () => {
  const projectPath = getProjectPath();

  if (fs.existsSync(projectPath)) {
    delDir(projectPath);
  }
  fs.mkdirSync(projectPath);
  fs.mkdirSync(projectPath + "\\res");
  fs.mkdirSync(projectPath + "\\res\\js");
  fs.mkdirSync(projectPath + "\\res\\css");
  fs.mkdirSync(projectPath + "\\res\\img");
  fs.mkdirSync(projectPath + "\\res\\img\\tmp");
  fs.mkdirSync(projectPath + "\\res\\img\\tmp\\icon");
  fs.mkdirSync(projectPath + "\\tmp");
  store.set({
    projectPath,
  });
};

export const renderElectronApiInvoke = {
  startServer: (): Promise<any> => {
    initServer();
    runServer();
    return store.get("serverUrl");
  },
  openUrl: (_: any, url: string): Promise<any> => {
    if (url === "unknown") return Promise.reject();
    shell.openExternal(url);
    return Promise.resolve();
  },
  openFolder: (_: any, folderPath: string) => {
    if (!fs.existsSync(folderPath)) {
      return Promise.reject("path does not exist! " + folderPath);
    }
    shell.openPath(folderPath);
    return Promise.resolve();
  },
  vscode: () => {
    const folderPath = getProjectPath();
    if (!fs.existsSync(folderPath)) {
      return Promise.reject("path does not exist!");
    }
    cmd.run(`code ${folderPath}`);
    return Promise.resolve();
  },
  openOriginFolder: () => {
    const folderPath = store.get("uploadFolderPath");
    if (!fs.existsSync(folderPath)) {
      return Promise.reject("path does not exist!");
    }
    shell.openPath(folderPath);
    return Promise.resolve();
  },
  openProjectFolder: (_: any, url: string) => {
    if (url === "unknown") return Promise.reject();
    if (!fs.existsSync(getProjectPath())) {
      return Promise.reject();
    }
    shell.openPath(getProjectPath());
    return Promise.resolve();
  },
  copyQualifiedStructure: (_: any, pathRoot: string): Promise<void> => {
    // console.log(pathRoot, getProjectPath());
    copyDir(pathRoot, getProjectPath());
    updateStructure();
    return Promise.resolve();
  },
  checkStructure: (_: any, pathRoot: string): Promise<void> => {
    const js = path.resolve(pathRoot, "res/js");

    if (!fs.existsSync(js)) {
      return Promise.reject("js path does not exist!");
    }
    const img = path.resolve(pathRoot, "res/img");
    if (!fs.existsSync(img)) {
      return Promise.reject("img path does not exist!");
    }
    const css = path.resolve(pathRoot, "res/css");
    if (!fs.existsSync(css)) {
      return Promise.reject("css path does not exist!");
    }
    return Promise.resolve();
  },
  detectIndex: (): Promise<string> => {
    updateStructure();
    if (fs.existsSync(path.join(getProjectPath(), "index.html"))) {
      return Promise.resolve("index.html");
    }
    return Promise.resolve(getStructure().html[0]);
  },
  backup: (_: any, src: string, dest: string): Promise<string> => {
    src = path.resolve(src);
    dest = path.join(dest, path.basename(src)); //src.substring(src.lastIndexOf("/") + 1)
    if (fs.existsSync(dest)) {
      return Promise.reject("dir already exist");
    }
    if (!fs.statSync(src).isDirectory()) {
      return Promise.reject("please choose directory instead!");
    }
    fs.mkdirSync(dest);

    // console.log(src, dest);

    copyDir(src, dest);
    return Promise.resolve("success");
  },

  setStorage: (_: any, key: string, val: string) => {
    store.set(key, val);
  },
  getStorage: (_: any, key: string): Promise<string> => {
    return Promise.resolve(store.get(key));
  },
  fileSelector: (_: any, type: "dir" | "file") => {
    const properties = [];
    properties.push(type === "dir" ? "openDirectory" : "openFile");
    return dialog.showOpenDialog({
      properties,
    });
  },
  videoPoster: async (_: any, file) => {
    const vid = file.filePaths[0];
    const fileName = path.basename(vid);
    const imgName = fileName.replace(".mp4", ".png");
    await cmd.runSync(
      `ffmpeg -i ${vid} -ss 00:00:01 -vframes 1 ${vid.replace(
        fileName,
        ""
      )}${imgName}`
    );

    return `
    <div class="videoBox" style="position: relative">
      <video src="res/img/${fileName}" muted autoplay loop></video>
      <img
        src="res/img/${imgName}"
        alt=""
        style="position: absolute; top: 0; left: 0; z-index: -1"
      />
    </div>
    `;
  },
  writeBack: (_: any, dest: string) => {
    delDir(dest);
    console.log("create dir: " + dest);
    try {
      fs.mkdirSync(dest);
      copyDir(getProjectPath(), dest);
    } catch (e) {
      console.error(e);
      setTimeout(() => {
        fs.mkdirSync(dest);
        copyDir(getProjectPath(), dest);
      }, 1000);
    }
    return Promise.resolve();
  },
  linkRes: () => {
    const structure = getStructure();

    structure.html.forEach((filePath) => {
      let fileBuffer = fs.readFileSync(filePath);
      let file = fileBuffer.toString();
      let folderTree: folderTreeType[] = JSON.parse(store.get("folderTree"));

      let fileObj = { filePath, file, fileBuffer, folderTree };

      htmlReLink(fileObj).forEach((val) => {
        file = file.replaceAll(val.origin, val.replaceWith);
      });

      fs.writeFileSync(filePath, file);
    });

    structure.css.forEach((filePath) => {
      // console.log(filePath, "filePath");

      let fileBuffer = fs.readFileSync(filePath);
      let file = fileBuffer.toString();
      let folderTree: folderTreeType[] = JSON.parse(store.get("folderTree"));

      let fileObj = { filePath, file, fileBuffer, folderTree };
      cssRelink(fileObj).forEach((val) => {
        file = file.replaceAll(val.origin, val.replaceWith);
      });
      fs.writeFileSync(filePath, file);
    });

    [
      ...structure.html,
      ...structure.img,
      ...structure.css,
      ...structure.js,
    ].forEach((val) => {
      if (fs.statSync(val).isDirectory()) {
        return;
      }
      if (val.endsWith(".db")) {
        fs.unlinkSync(val);
      } else {
        removeIdFromFile(val);
      }
    });
    return Promise.resolve();
  },
};

export const getStructure: () => fileStructureInterface = () =>
  JSON.parse(store.get("projectStructure"));
export const getRawStructure: () => fileStructureInterface = () =>
  JSON.parse(store.get("projectStructureRaw"));

export const renderElectronApiSend = {
  initServer,
  stopServer: () => closeServer(),
  setUploadFolderPath: (_: any, path: string) => {
    store.set("uploadFolderPath", path);
  },
  renameTitle: (_: any, newName: string) => {
    const structure = getStructure();
    structure.html.forEach((filePath) => {
      if (!fs.existsSync(filePath)) return;
      let file = fs.readFileSync(filePath).toString();
      fs.writeFileSync(filePath, changeTitle(newName, file));
    });
  },
  rename: (_: any, oldName: string, newName: string) => {
    const structure = getStructure();
    structure.html.forEach((filePath) => {
      if (!fs.existsSync(filePath)) return;
      let file = fs.readFileSync(filePath).toString();
      fs.writeFileSync(
        filePath,
        changeTitle(newName, file.replaceAll(oldName, newName))
      );
    });
  },
  integration: (): void => {
    const structure = getStructure();
    structure.html.forEach((filePath, index) => {
      let file = fs.readFileSync(filePath).toString();
      fs.writeFileSync(filePath, htmlIntegration(file, index));
    });
    updateStructure();
  },
  clearLink: (): void => {
    const structure = getStructure();
    structure.html.forEach((filePath, index) => {
      let file = fs.readFileSync(filePath).toString();
      fs.writeFileSync(filePath, cleanHtmlLinks(file, index));
    });
    structure.css.forEach(async (filePath, index) => {
      let file = fs.readFileSync(filePath).toString();
      fs.writeFileSync(filePath, await cleanCssLinks(file, index));
    });
  },
  footer: (_: any, indexName: string): void => {
    const footerPath = path.resolve(getTemplatesPath(), "footer");
    const html = fs
      .readFileSync(path.resolve(footerPath, "footerHtml.txt"))
      .toString();
    const css = fs
      .readFileSync(path.resolve(footerPath, "footerCss.txt"))
      .toString();
    copyIfNotExist(
      path.resolve(footerPath, "footerBg.png"),
      path.resolve(getProjectImgPath(), "footerBg.png")
    );
    copyIfNotExist(
      path.resolve(footerPath, "footerLogo.png"),
      path.resolve(getProjectImgPath(), "footerLogo.png")
    );
    let filePath = path.join(getProjectPath(), indexName);
    const indexFile = fs.readFileSync(filePath).toString();
    fs.writeFileSync(
      filePath,
      quoteCss(indexFile, css, "myFooter.css").replace(
        /<\/body>/gi,
        `${html}\n</body>`
      )
    );
  },
  zoom: (_: any, val: string): void => {
    const pro = getProjectPath();
    const filePath = path.join(pro, val);
    let file = fs.readFileSync(filePath).toString();
    const from = path.resolve(getTemplatesPath(), "zoom/resolution.js");
    const to = path.join(pro, "/res/js/resolution.js");
    // console.log(from, to);
    // fs.copyFileSync(from, to);
    copyIfNotExist(from, to);
    fs.writeFileSync(
      filePath,
      file.replace(
        "<head>",
        "<head>\r\t\n<script src='res/js/resolution.js'></script>"
      )
    );
  },
  addIcon: (_: any, val: string): void => {
    const pro = getProjectImgPath();

    let filePath = path.join(getProjectPath(), val);
    let file = fs.readFileSync(filePath).toString();

    const icoFile = getRawStructure().img.findIndex((val) =>
      val.endsWith("ico")
    );
    if (icoFile != -1 && getRawStructure().img[icoFile] !== "favicon.ico") {
      fs.copyFileSync(
        path.resolve(getProjectImgPath(), getRawStructure().img[icoFile]),
        path.resolve(getProjectImgPath(), "favicon.ico")
      );
    } else {
      const from = path.resolve(getTemplatesPath(), "header/favicon.ico");
      const to = path.join(pro, "favicon.ico");
      copyIfNotExist(from, to);
    }

    file = file.replace(
      /(<link(.|\r|\n)*?rel=("|')icon("|')(.|\r|\n)*?>)/gi,
      '<head>\r\t\n<link rel="icon"  href="res/img/favicon.ico" type="image/x-icon" >'
    );

    if (file.indexOf("favicon.ico") === -1) {
      file = file.replace(
        /(<head>)/i,
        '<head>\r\t\n<link rel="icon"  href="res/img/favicon.ico" type="image/x-icon" >'
      );
    }

    fs.writeFileSync(filePath, file);
  },
  addQQ: (_: any, indexName: string) => {
    const sourcePath = path.resolve(getTemplatesPath(), "qq");
    const data = fs.readFileSync(sourcePath).toString();
    let filePath = path.join(getProjectPath(), indexName);
    const indexFile = fs.readFileSync(filePath).toString();
    fs.writeFileSync(filePath, appendToBody(indexFile, data));
  },
  unlinkImg: () => {
    unlinkImg(getRawStructure());
  },
  addMusic: (_: any, indexName: string): void => {
    let filePath = path.join(getProjectPath(), indexName);
    const indexFile = fs.readFileSync(filePath).toString();
    fs.writeFileSync(filePath, addMusicToIndex(indexFile));
  },
  test: () => {},
  electronProjectFolder: () => {
    shell.openPath(path.resolve("./"));
  },

  openCmdWithPath: () => {
    const folderPath = getProjectPath();
    // cmd.runSync(`cd ${folderPath} && start cmd`);
    cmd.run(`cd ${folderPath} && start cmd`);
  },
  beautify: () => {},
  categoryEquipments: (_: any, heightLimit: number) => {
    const equipFolder = getProjectEquipPath();
    const iconFolder = getProjectIconPath();
    const list = fs.readdirSync(equipFolder) as string[];
    list.forEach((val) => {
      const item = path.join(equipFolder, val);
      if (item.endsWith("gif")) {
        fs.rename(item, path.join(getProjectImgPath(), val), () => {});
        return;
      }
      if (fs.statSync(item).isDirectory()) return;
      const dimensions = sizeOf(item);

      if (dimensions.height < heightLimit) {
        fs.rename(item, path.join(iconFolder, val), () => {});
      }
    });
  },
};

export type electronApiSendType = typeof renderElectronApiSend;
export type electronApiInvokeType = typeof renderElectronApiInvoke;
